package com.xnx.bincker.leader.core.repository;

import com.xnx.bincker.leader.domain.CustomPage;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;

import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import java.util.Iterator;
import java.util.List;

/**
 * 基础DAO实现
 * @param <T>
 * @param <ID>
 */
@NoRepositoryBean
public class BasicRepositoryImpl<T, ID> extends SimpleJpaRepository<T, ID> implements BasicRepository<T, ID> {
	private EntityManager entityManager;
	public BasicRepositoryImpl(Class<T> domainClass, EntityManager em) {
		super(domainClass, em);
		this.entityManager = em;
	}

    /**
     * 主要将默认的Page实现改为CustomPage，做JSON属性过滤
     */
    public Page<T> findAll(Pageable pageable) {
        return pageable.isUnpaged() ? new CustomPage<>(this.findAll()) : this.findAll((Specification<T>)null, pageable);
    }

    /**
     * 主要将默认的Page实现改为CustomPage，做JSON属性过滤
     */
    public Page<T> findAll(@Nullable Specification<T> spec, Pageable pageable) {
        TypedQuery<T> query = this.getQuery(spec, pageable);
        return pageable.isUnpaged() ? new CustomPage<>(query.getResultList()) : this.readPage(query, this.getDomainClass(), pageable, spec);
    }

    /**
     * 主要将默认的Page实现改为CustomPage，做JSON属性过滤
     */
    protected <S extends T> Page<S> readPage(TypedQuery<S> query, Class<S> domainClass, Pageable pageable, @Nullable Specification<S> spec) {
        if (pageable.isPaged()) {
            query.setFirstResult((int)pageable.getOffset());
            query.setMaxResults(pageable.getPageSize());
        }

        return new CustomPage<>(PageableExecutionUtils.getPage(query.getResultList(), pageable, () -> executeCountQuery(this.getCountQuery(spec, domainClass))));
    }

    private static long executeCountQuery(TypedQuery<Long> query) {
        Assert.notNull(query, "TypedQuery must not be null!");
        List<Long> totals = query.getResultList();
        long total = 0L;

        Long element;
        for(Iterator var4 = totals.iterator(); var4.hasNext(); total += element == null ? 0L : element) {
            element = (Long)var4.next();
        }

        return total;
    }
}
